/*******************************************************************************
 * Copyright (c) 2012, 2013 XML-Print Project.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     XML-Print Project - initial API and implementation
 ******************************************************************************/
package info.xmlprint.core.format;

import info.xmlprint.run.RuntimeUtil;
import info.xmlprint.util.FileUtil;
import info.xmlprint.util.Utf8ToAnsi;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Serializable;
import java.text.Collator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Shell;

public class Format implements Serializable, Comparable<Format> {

	private static final long serialVersionUID = 4286892755469709541L;

	private String id = "";

	// name der Format
	private String name;

	// ignore oder standard
	private String type = "";

	// Anfang als inline. weitere Möglichkeiten: block, footnote, List. ......
	private String fo_category = "inline";

	private FormatGroup formatGroup;

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public void replaceWith(Format f) {
		this.setId(f.getId());
		this.setFoCategory(f.getFoCategory());
		this.setName(f.getName());
		this.setType(f.getType());

		// attribute
		for (String key : f.getAttributeNames()) {
			this.setAttribute(key, f.getAttribute(key));
			this.setInherit(key, f.getInherit(key));
		}
		// foot attribute
		for (String key : f.getFootnoteAttributNames()) {
			this.setFootnoteAttribute(key, f.getFootnoteAttribute(key));
		}

	}

	public FormatGroup getFormatGroup() {
		return formatGroup;
	}

	public void setFormatGroup(FormatGroup fg) {
		this.formatGroup = fg;
	}

	/*
	 * // block oder inline private boolean isBlock = false; private boolean
	 * isFootnote = false;
	 */

	// Attribute des Formats, die mit Formatierungen zu tun haben
	private String[] attrArray = new String[] { "font-family", "font-size",
			"font-stretch", "font-style", "font-weight", "font-variant",
			"letter-spacing", "line-height", "margin-left", "margin-right",
			"space-after.maximum", "space-after.minimum",
			"space-after.optimum", "space-before.maximum",
			"space-before.minimum", "space-before.optimum", "text-align",
			"text-indent", "text-decoration", "color", "text-addition-before",
			"text-addition-after", "baseline-shift", "language", "country",
			"hyphenation-remain-character-count",
			"hyphenation-push-character-count", "hyphenate",
			"hyphenation-character", "column-count", "column-gaps",
			"column-directions", "column-widths", "break-after", "pagemaster" };

	// Container for attributes and values
	private Map<String, String> attrMap = new HashMap<String, String>();

	private String[] footnoteAttrArray = new String[] { "fn-numberingstyle",
			"fn-prefix", "fn-postfix", "fn-type", "fn-reset", "fn-refSystem",
			"fn-baseline-shift", "fn-seprule-bool", "fn-seprule-width", 
			"fn-seprule-width-long", "fn-seprule-color", "fn-seprule-thickness", 
			"fn-separator-mult"};

	private Map<String, String> footnoteAttrMap = new HashMap<String, String>();

	private Map<String, Boolean> inheritMap = new HashMap<String, Boolean>();

	public Format() {
		init();
	}

	public Format(String name) {
		this.name = name;
		init();
	}

	/*
	 * public boolean isBlock() { return isBlock; }
	 * 
	 * public void setBlock(boolean isBlock) { this.isBlock = isBlock; }
	 * 
	 * 
	 * public boolean isFootnote() { return isFootnote; }
	 */

	public String getFoCategory() {
		return fo_category;
	}

	public void setFoCategory(String fo_category) {
		this.fo_category = fo_category;
	}

	public void init() {
		for (String s : attrArray) {
			attrMap.put(s, "%@%");
		}

		for (String s : footnoteAttrArray) {
			footnoteAttrMap.put(s, "");
		}

		/*
		 * if (this.getType().equals("standard")) { //für Standard "inherit"
		 * ausschalten for (String s : attrArray) { inheritMap.put(s, false); }
		 * } else { for (String s : attrArray) { inheritMap.put(s, true); } }
		 */
		// TODO Neue Formate sollen die Einstellung von "Standard" übernehmen.
		// Bei der Erstellung von
		// "Standard" und "Ignore" existieren aber noch keine Formatgruppe
		try {
			for (String s : attrArray) {
				inheritMap.put(s, this.getFormatGroup().getStandardFormat()
						.getInherit(s));
			}
		} catch (NullPointerException ne) {
			for (String s : attrArray) {
				inheritMap.put(s, true);
			}
		}

		/*
		 * if (this.getType().equals("standard") ||
		 * this.getType().equals("ignore")) { for (String s : attrArray) {
		 * inheritMap.put(s, true); } } else { for (String s : attrArray) {
		 * inheritMap.put(s,
		 * this.getFormatGroup().getStandardFormat().getInherit(s)); } }
		 */
	}

	// MS Format auf Basis eines anderen
	public Format(String name, String df) {
		this.name = name;
		FormatGroup fg = RuntimeUtil.getInstance().getCurrentPrintProject()
				.getFormatGroup();
		for (String s : attrArray) {
			attrMap.put(s, fg.getFormatByName(df).getAttribute(s));
		}
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getName() {
		return this.name;
	}

	public void setType(String type) {
		this.type = type;
	}

	public String getType() {
		return type;
	}

	public String getFormatedName() {
		return Utf8ToAnsi.Decode(this.name);
		// return this.name.replaceAll(" ", "_OOO_");
	}

	/*
	 * set Werte einer Attribut der Format
	 */
	public void setAttribute(String key, String value) {
		if (key != null && !key.equals(""))
			attrMap.put(key, value);
	}

	/*
	 * get Werte einer Attribut der Format
	 */
	public String getAttribute(String key) {
		String s = attrMap.get(key);
		if (s == null)
			s = "";

		// Werte von Standardformat
		if (s.equals("%@%")) {
			if (formatGroup != null) {
				Format f = formatGroup.getStandardFormat();
				if (!this.equals(f)) {
					return f.getAttribute(key);
				}
			}

			return "";
		}

		return s;
	}

	//
	public String getRealAttribute(String key) {
		String s = attrMap.get(key);

		if (s == null)
			s = "";

		return s;
	}

	public String getFootnoteAttribute(String key) {
		String s = footnoteAttrMap.get(key);
		if (s == null)
			s = "";
		return s;
	}

	public void setFootnoteAttribute(String key, String value) {
		if (key != null && !key.equals(""))
			footnoteAttrMap.put(key, value);
	}

	public int compareTo(Format compareObject) { // to sort formats according to
													// their name
		Collator collator = null;
		collator = Collator.getInstance(java.util.Locale.GERMAN);
		collator.setStrength(Collator.SECONDARY);
		return collator.compare(getName(), compareObject.getName());
	}

	public boolean isInherit(String key) {
		return (inheritMap.get(key));
	}

	public void setInherit(String key, Boolean bool) {
		inheritMap.put(key, bool);
	}

	public Boolean getInherit(String key) {
		return (inheritMap.get(key));
	}

	public void switchInherit(String key) {
		inheritMap.put(key, !inheritMap.get(key));
	}

	/*
	 * Dialog Fenster fuer Format speichern (nur einzelne Format)
	 */
	public void saveDialog() {
		FileDialog fileDialog = new FileDialog(Display.getCurrent()
				.getActiveShell(), SWT.SAVE);
		fileDialog.setFilterExtensions(new String[] { "*.xml", "*.*" });
		String fName = fileDialog.open();
		if (!fName.isEmpty()) {
			save2file(fName);
		}

	}

	/*
	 * die Format in xml speichern
	 */
	public void save2file(String fName) {
		OutputFormat format = OutputFormat.createPrettyPrint();
		format.setEncoding("utf-8");
		format.setOmitEncoding(false);
		format.setExpandEmptyElements(false);
		File file = new File(fName);

		Document doc = DocumentHelper.createDocument();
		Element root = doc.addElement("format");
		root.addElement("name").setText(this.name);
		for (String s : attrArray) {
			root.addElement(s).setText(attrMap.get(s));
		}

		for (String s : attrArray) {
			root.addElement("inherit_" + s).setText(
					inheritMap.get(s).toString());
		}

		XMLWriter writer = null;
		try {
			writer = new XMLWriter(new FileWriter(file), format);
			writer.write(doc);
			writer.close();
		} catch (IOException e) {
			Logger.getLogger(this.getClass().getName()).error("", e);
			e.printStackTrace();
		}

	}

	/*
	 * set Attribute-Array der Format
	 * 
	 * public void setFormatArr(String[] formatArr) { this.attrArray =
	 * formatArr; }
	 */

	/*
	 * get Attribute-Array der Format
	 */
	public String[] getAttributeNames() {
		return attrArray;
	}

	public String[] getFootnoteAttributNames() {
		return footnoteAttrArray;
	}

	/*
	 * Dialog Fenster fuer Format-Xml einlesen
	 */
	public void readDialog() {
		FileDialog fileDialog = new FileDialog(Display.getCurrent()
				.getActiveShell(), SWT.OPEN);
		fileDialog.setFilterExtensions(new String[] { "*.xml", "*.*" });
		String fName = fileDialog.open();
		if (!fName.isEmpty()) {
			readFromFile(fName);
			formatPrintln();
		}

	}

	/*
	 * Format-Xml einlesen
	 */
	public void readFromFile(String fName) {
		File file = new File(fName);
		SAXReader reader = new SAXReader();
		Document doc = null;
		try {
			doc = reader.read(file);
		} catch (DocumentException e) {
			e.printStackTrace();
		}
		Element root = doc.getRootElement();
		attrMap.put("name", this.name);
		for (String s : attrArray) {
			Element e = root.element(s);
			attrMap.put(s, e.getText());
		}

		for (String s : attrArray) {
			Element e = root.element("inherit_" + s);
			if (e.getText().equals("true")) {
				inheritMap.put(s, true);
			} else {
				inheritMap.put(s, false);
			}
		}

	}

	public void formatPrintln() {
		System.out.println(map2String());
	}

	public String map2String() {
		String s = "";
		Iterator<Entry<String, String>> it = attrMap.entrySet().iterator();
		while (it.hasNext()) {
			String key = it.next().getKey();
			s += key + ":" + attrMap.get(key) + "\n";
		}
		return s;
	}

	public static void main(String args[]) {
		Display display = new Display();
		Shell shell = new Shell(display);
		shell.setLayout(new FillLayout());
		shell.open();

		Format f = new Format();
		f.setName("f1");
		f.readDialog();

		while (!shell.isDisposed()) {
			if (!display.readAndDispatch())
				display.sleep();
		}

	}

	public Format objClone() {
		Format newF = (Format) FileUtil.objClone(this);
		return newF;
	}
}
